package com.mandao.concurrency.interviewset.pooldemo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
* Description:
 *      多綫程查庫
* @author woniu
*/
public class MutiThreadQuery {

    public List<Object> queryMethedOne() {

        ThreadPoolExecutor executor =
                new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES,
                        new ArrayBlockingQueue<Runnable>(10),
                        new ThreadPoolExecutor.CallerRunsPolicy());

        System.out.println("start thread pool...");

        List<Object> resultList = new ArrayList<>();

        //查询页数（批次）
        int pageIndex = 0;
        int n = 30;

        //当页数小于n（总线程数）时，跳出
        do {
            MergeRunnable mr = new MergeRunnable(resultList, pageIndex);
            executor.execute(mr);
            System.out.println("pageIndex:"+pageIndex);
            pageIndex++;
        }while(pageIndex < n);

        //不能再提交新任务
        executor.shutdown();

        boolean loop = true;

        try {
            do {//等待所有任务完成

                System.out.println("线程池中线程数目:" + executor.getPoolSize());

                System.out.println("队列中等待执行的任务数目:" +  executor.getQueue().size());

                System.out.println("已执行完的任务数目:" + executor.getCompletedTaskCount());

                System.out.println("当前的resultList数量:" + resultList.size());

                System.out.println("总共记录数:" + "xxx");

                //阻塞，直到线程池所有的任务结束，2秒判断一次
                // awaitTermination 线程池一种优雅关闭的方法 并允许关闭声明后新任务能提交
                loop = !executor.awaitTermination(2, TimeUnit.SECONDS);

            }while(loop);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return resultList;
    }

    class MergeRunnable implements Runnable{

        private List<Object> allRest;

        private int pageIndex;

        MergeRunnable(List<Object> resultList, int pageIndex) {
            this.allRest = resultList;
            this.pageIndex = pageIndex;
        }

        @Override
        public void run() {
            System.err.println(Thread.currentThread().getName() +" query data start...");
            List<Object> tempPageRest = queryFromDataBase(pageIndex);
            synchronized(allRest) {
                allRest.addAll(tempPageRest);
            }
            System.err.println(Thread.currentThread().getName() +" query data end...");
        }

    }

    private List<Object> queryFromDataBase(int pageIndex) {
        // TODO do some operation from database
        try {
            Thread.sleep(10*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        List<Object> test = new ArrayList<>();
        return test;
    }

    //----------------------------华丽的分割线----以下是第二种写法，为了测试和第一种有没有性能上的差别---------

    public List<Object> queryMethedTwo() {

        ThreadPoolExecutor executor =
                new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES,
                        new ArrayBlockingQueue<Runnable>(10),
                        new ThreadPoolExecutor.CallerRunsPolicy());

        System.out.println("start thread pool...");

        List<Object> resultList = new ArrayList<Object>();

        //查询页数（批次）
        int pageIndex = 0;
        //当页数小于n（总线程数）时，跳出
        int n = 30;

        CountDownLatch latch = new CountDownLatch(n);

        for (int i = 0; i < n; i++) {
            MergeRunnable1 mr1 = new MergeRunnable1(resultList, pageIndex, latch);
            executor.execute(mr1);
            System.out.println("pageIndex:"+pageIndex);
            pageIndex++;
        }
        executor.shutdown();

        try {
            latch.await(2,TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return resultList;

    }

    class MergeRunnable1 implements Runnable{

        private List<Object> allRest;
        private int pageIndex;
        private CountDownLatch latch;

        MergeRunnable1(List<Object> resultList, int pageIndex, CountDownLatch latch) {
            this.allRest = resultList;
            this.pageIndex = pageIndex;
            this.latch = latch;
        }

        @Override
        public void run() {
            System.err.println(Thread.currentThread().getName() +" query data start...");
            List<Object> tempPageRest = queryFromDataBase(pageIndex);
            synchronized(allRest) {
                allRest.addAll(tempPageRest);
            }
            latch.countDown();
            System.err.println(Thread.currentThread().getName() +" query data end...");
        }

    }

    //----------------------------华丽的分割线----以下是第二种写法，为了测试和第一种有没有性能上的差别---------

    public static void main(String[] args) {

        MutiThreadQuery m = new MutiThreadQuery();
        long a = System.currentTimeMillis();

//        m.queryMethedOne();

        m.queryMethedTwo();

        System.out.println("#################:"+(System.currentTimeMillis() - a)+"ms");

    }


}
